#include <iostream>
#include <string.h>

using std::cout;
using std::endl;

//执行delete（中的free），先去执行析构函数，然后再返回来释放指针对象

void *operator new(size_t sz){
    cout<<"void *operator new(size_t)"<<endl;
    //用malloc申请未初始化空间
    void *pret=malloc(sz);
    return pret;
}
    
void operator delete(void *ptr){
    cout<<"void operator delete(void * ptr)"<<endl;
    free(ptr);
}

class Student{
public:
    Student(const char *name,int id)
    : _name(new char[strlen(name) + 1 ]())
    , _id(id)
    {
        cout<<"构造函数"<<endl;
        strcpy(_name,name);
    }
    
    //放在里面的new和delete只针对Student这个类
    //它们没有this指针，是静态成员函数
    //最好放在类的外面
/*    
    static void *operator new(size_t sz){
        cout<<"void *operator new(size_t)"<<endl;
        //用malloc申请未初始化空间
        void *pret=malloc(sz);
        //并调用该类型的构造函数，但我不知道是不是在malloc调用了
        
        return pret;
    }
    
    static void operator delete(void *ptr){
        cout<<"void operator delete(void * ptr)"<<endl;
        free(ptr);
    }
*/
    void print() const{
        if(_name){
            cout<<_name<<"  "<<_id<<endl;
        }
    }

    ~Student(){
        if(_name){
            cout<<"先析构"<<endl;
            delete []_name;
            _name=nullptr;
        }
    }

private:
    char *_name;
    int _id;

};

void test(){
    
    /*Student stu=Student("xiaowang",4200);
    stu.print();
    cout<<endl;*/

    //尽管在使用new运算符时没有显式传递size_t参数，
    //但new运算符内部会根据要创建的对象的类型确定所需的大小，并将其传递给operator new
    //这样可以实现根据要创建的对象类型进行动态内存分配，而无需程序员显式指定大小。
    Student *pstu=new Student("xiaohong",4201);
    //pstu本身在栈上，而这个Student“临时对象”是new出来的，在堆上，调用了构造函数
    //"xiaohong"的空间在初始化列表中也被new出来，也在堆上，
    
    pstu->print();
    cout<<endl;

    //对于堆对象，delete对象 > 析构函数，后者只销毁了数据成员，对象本身也要在之后销毁
    //对于栈对象，两者等价
    delete pstu;
    pstu=nullptr;

}

int main()
{   
    test();

    return 0;
}

